package com.bytz.modules.cms.auditBatch.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bytz.common.system.base.service.impl.AbstractCrudService;
import com.bytz.common.util.PageUtils;
import com.bytz.common.util.mentity.EntityMergeInfoV2;
import com.bytz.common.util.mentity.util.MergeEntityOptions;
import com.bytz.common.util.mentity.util.MergeEntityUtil;
import com.bytz.modules.cms.auditBatch.model.AuditBatchModel;
import com.bytz.modules.cms.productLine.entity.ProductLine;
import com.bytz.modules.cms.productLine.service.IProductLineService;
import com.bytz.modules.cms.user.constants.AuditBatchConstants;
import com.bytz.modules.cms.user.entity.AuditBatch;
import com.bytz.modules.cms.user.mapper.AuditBatchMapper;
import com.bytz.modules.cms.user.model.IChangeEntity;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public abstract class AbstractAuditBatchService<CE extends IChangeEntity> extends AbstractCrudService<AuditBatchMapper, AuditBatch, AuditBatchModel<CE>> implements IAdminAuditBatchService<CE> {

    /**
     * 获取change表的service
     */
    protected abstract IChangeService<CE> getChangeService();

    /**
     * 获取type字段的字符串
     */
    protected abstract String getType();

    @Autowired
    private IProductLineService productLineService;

    @Override
    protected AuditBatchModel<CE> insertSaveObject(AuditBatchModel<CE> saveRo) {
        setLineInfo(saveRo);
        save(saveRo);
        return saveRo;
    }

    @Override
    protected AuditBatchModel<CE> updateSaveObject(AuditBatchModel<CE> saveRo) {
        setLineInfo(saveRo);
        updateById(saveRo);
        return saveRo;
    }

    private void setLineInfo(AuditBatch batch) {
        Optional<ProductLine> line = productLineService.getLoginUserLine();
        if (line.isPresent()) {
            batch.setProductLineId(line.get().getId());
            batch.setProductLineName(line.get().getProductLineName());
        }
    }

    @Override
    protected AuditBatchModel<CE> saveOthers(AuditBatchModel<CE> saveRo) {
        if (saveRo.getChangeList() == null) {
            saveRo.setChangeList(new ArrayList<>());
        }
        saveRo.getChangeList().forEach(item -> {
            item.setAuditBatchId(saveRo.getId());
            item.setEffectTime(saveRo.getEffectTime());
        });
        EntityMergeInfoV2<CE> mergeInfo = MergeEntityUtil.calculateEntityMergeInfo(
                saveRo.getChangeList(),
                getChangeService().getByBatchId(saveRo.getId()),
                MergeEntityOptions.<CE>builder().build()
        );
        MergeEntityUtil.doDbMerge(mergeInfo, getChangeService());
        return saveRo;
    }

    @Override
    protected boolean deleteEntity(AuditBatch entity) {
        return removeById(entity);
    }

    @Override
    protected void deleteOthers(AuditBatch entity) {
        getChangeService().removeByBatchId(entity.getId());
    }

    @Override
    public IPage<AuditBatchModel> queryPage(Page<AuditBatch> page, QueryWrapper<AuditBatch> initQueryWrapper) {

        initQueryWrapper.lambda().orderByDesc(AuditBatch::getUpdateTime);

        Page<AuditBatch> resultPage = page(page, initQueryWrapper);

        return PageUtils.convertPage(resultPage, AuditBatchModel.class, (out, in) -> {
            out.setCanEdit(StringUtils.equals(in.getStatus(), AuditBatchConstants.Status.CAO_GAO));
        });
    }

    @Override
    public AuditBatchModel<CE> queryById(String id) {

        AuditBatchModel<CE> result = new AuditBatchModel<>();

        BeanUtils.copyProperties(getById(id), result);
        result.setChangeList(getChangeService().getByBatchId(id));

        return result;
    }

    @Override
    public AuditBatchModel<CE> storage(AuditBatchModel<CE> model) {
        model.setType(getType());
        model.setStatus(AuditBatchConstants.Status.CAO_GAO);
        return saveOrUpdateSaveObject(model, false);
    }

    @Override
    public AuditBatchModel<CE> submit(AuditBatchModel<CE> model) {
        model.setType(getType());
        model.setStatus(AuditBatchConstants.Status.DAI_SHENG_XIAO);
        return saveOrUpdateSaveObject(model, false);
    }

    @Override
    public void syncChange() {
        List<String> batchIds = getWaitingSyncBatchByType(getType());
        for (String batchId : batchIds) {
            try {
                getChangeService().syncChange(batchId);
            } catch (Exception e) {
                log.error(getType() + "同步失败, batchId:" + batchId, e);
            }
        }
    }

    /**
     * 根据类型查找所有待同步的batch的id
     */
    private List<String> getWaitingSyncBatchByType(String type) {
        return lambdaQuery()
                .eq(AuditBatch::getType, type)
                .eq(AuditBatch::getStatus, AuditBatchConstants.Status.DAI_SHENG_XIAO)
                .lt(AuditBatch::getEffectTime, LocalDateTime.now().plusDays(1).toLocalDate())
                .list().stream()
                .map(AuditBatch::getId)
                .collect(Collectors.toList());
    }

    @Override
    public List<CE> importExcel(List<CE> models) {
        return getChangeService().importExcel(models);
    }
}
